package git.soulbgm.utils;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Calendar;

/**
 * @author 贺瑞杰
 * @version V1.0
 * @date 2018-06-04 14:13
 * @description Byte、ByteBuf 等的工具类
 */
public class ByteUtil {

    /**
     * UTF-8字符集
     */
    private final static String CHARSET_UTF8 = "UTF-8";

    /**
     * GBK字符集
     */
    private final static String CHARSET_GBK = "GBK";

    /**
     * ISO-8859-1字符集
     */
    private final static String CHARSET_ISO = "ISO-8859-1";

    public static boolean isEmpty(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return true;
        }
        return false;
    }

    public static boolean isNotEmpty(byte[] bytes) {
        if (bytes != null && bytes.length > 0) {
            return true;
        }
        return false;
    }

    /**
     * String转ByteBuf
     *
     * @param str
     * @return
     */
    public static ByteBuf stringToByteBuf(String str) {
        return Unpooled.copiedBuffer(str, CharsetUtil.UTF_8);
    }

    /**
     * String转byte[] UTF-8编码转换
     *
     * @param str 字符串
     * @return byte[]
     */
    public static byte[] stringToByteArray(String str) {
        return stringToByteArray(str, new byte[]{}, CHARSET_UTF8);
    }

    /**
     * String转byte[]
     *
     * @param str         字符串
     * @param defaultData 如果字符串为null转换的默认返回值
     * @param charset     转换的编码
     * @return byte[]
     */
    public static byte[] stringToByteArray(String str, byte[] defaultData, String charset) {
        if (str != null) {
            return str.getBytes(Charset.forName(charset));
        }
        return defaultData;
    }

    /**
     * ByteBuf转byte[]
     *
     * @param byteBuf
     * @return
     */
    public static byte[] byteBufToByteArray(ByteBuf byteBuf) {
        return ByteBufUtil.getBytes(byteBuf);
    }

    /**
     * 生成byte[]版时间
     * 年、月、日、时、分、秒、毫秒
     *
     * @return
     */
    public static byte[] createNow() {
        Calendar now = Calendar.getInstance();
        byte[] year = decimalToByteArray(now.get(Calendar.YEAR));
        byte[] month = decimalToByteArray(now.get(Calendar.MONTH) + 1);
        byte[] day = decimalToByteArray(now.get(Calendar.DAY_OF_MONTH));
        byte[] hour = decimalToByteArray(now.get(Calendar.HOUR_OF_DAY));
        byte[] minute = decimalToByteArray(now.get(Calendar.MINUTE));
        byte[] second = decimalToByteArray(now.get(Calendar.SECOND));
        byte[] millisecond = decimalToByteArray(now.get(Calendar.MILLISECOND), 2);
        return byteMergerAll(year, month, day, hour, minute, second, millisecond);
    }

    /**
     * 生成byte[]版时间
     * 年、月、日
     *
     * @return
     */
    public static byte[] createDay() {
        Calendar now = Calendar.getInstance();
        byte[] year = decimalToByteArray(now.get(Calendar.YEAR));
        byte[] month = decimalToByteArray(now.get(Calendar.MONTH) + 1);
        byte[] day = decimalToByteArray(now.get(Calendar.DAY_OF_MONTH));
        return byteMergerAll(year, month, day);
    }

    /**
     * byte[]转ByteBuf
     *
     * @param data
     * @return
     */
    public static ByteBuf byteArrayToByteBuf(byte[] data) {
        return Unpooled.copiedBuffer(data);
    }

    /**
     * 将一个byte[]数据替换指定位置的byte位置
     *
     * @param sourceData  - 源数据
     * @param replaceData - 替换数据
     * @param start       - 开始位置
     * @param end         - 结束位置
     * @return 新的byte[]
     */
    public static byte[] changeByte(byte[] sourceData, byte[] replaceData, int start, int end) {
        if (isEmpty(sourceData) || isEmpty(replaceData)) {
            return null;
        }
        return byteMergerAll(getByte(sourceData, 0, start), replaceData, getByte(sourceData, end, sourceData.length));
    }

    /**
     * 从byte[]中抽取新的byte[]
     *
     * @param data  - 源数据
     * @param start - 开始位置
     * @param end   - 结束位置
     * @return 新byte[]
     */
    public static byte[] getByte(byte[] data, int start, int end) {
        byte[] ret = new byte[end - start];
        System.arraycopy(data, start, ret, 0, end - start);
        return ret;
    }

    /**
     * 10进制转16进制
     *
     * @param num
     * @return
     */
    public static String decimalToHexadecimal(long num) {
        return Long.toHexString(num);
    }

    /**
     * 将16进制字符串转10进制数字 Long类型
     *
     * @param num
     * @return
     */
    public static long hexadecimalToDecimalLong(String num) {
        return Long.parseLong(num, 16);
    }

    /**
     * 将16进制字符串转10进制数字 Integer类型
     *
     * @param num
     * @return
     */
    public static int hexadecimalToDecimalInteger(String num) {
        return Integer.parseInt(num, 16);
    }

    /**
     * 将byte[] 转为 16进制字符串
     *
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 将16进制字符串装为byte[]
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || "".equals(hexString)) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int i1 = 2;
        if (hexString.length() % i1 != 0) {
            hexString = "0" + hexString;
        }
        int length = hexString.length() / 2;

        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }


    /**
     * 将10进制数值转换为byte数组并指定占位数如果10进制数不够0来占位
     *
     * @param num
     * @return
     */
    public static byte[] decimalToByteArray(long num, int occupation) {
        byte[] bytes = hexStringToBytes(decimalToHexadecimal(num));
        if (bytes.length < occupation) {
            return byteMergerAll(createOccupation(occupation - bytes.length), bytes);
        }
        return bytes;
    }

    /**
     * 将10进制数值转换为byte数组
     *
     * @param num
     * @return
     */
    public static byte[] decimalToByteArray(long num) {
        return hexStringToBytes(decimalToHexadecimal(num));
    }

    /**
     * 创建占位byte
     *
     * @param occupationLength
     * @return
     */
    public static byte[] createOccupation(int occupationLength) {
        byte[] bytes = new byte[occupationLength];
        return bytes;
    }

    /**
     * char转byte
     *
     * @param c
     * @return
     */
    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 转换10进制 long型
     * 过程：
     * 1、将源byte转成新byte
     * 2、新byte转成16进制字符串
     * 3、16进制字符串转10进制数字
     *
     * @param completeDataPacket 源byte
     * @param startPosition      开始byte位
     * @param endPosition        结束byte位
     * @return
     */
    public static long changeDecimalLong(byte[] completeDataPacket, int startPosition, int endPosition) {
        return hexadecimalToDecimalLong(bytesToHexString(getByte(completeDataPacket, startPosition, endPosition)));
    }

    /**
     * 转换10进制 int型
     * 过程：
     * 1、将源byte转成新byte
     * 2、新byte转成16进制字符串
     * 3、16进制字符串转10进制数字
     *
     * @param completeDataPacket 源byte
     * @param startPosition      开始byte位
     * @param endPosition        结束byte位
     * @return
     */
    public static int changeDecimalInteger(byte[] completeDataPacket, int startPosition, int endPosition) {
        return hexadecimalToDecimalInteger(bytesToHexString(getByte(completeDataPacket, startPosition, endPosition)));
    }

    /**
     * 将多个byte[]组合成一个byte[]
     *
     * @param values
     * @return
     */
    public static byte[] byteMergerAll(byte[]... values) {
        int lengthByte = 0;
        for (int i = 0; i < values.length; i++) {
            lengthByte += values[i].length;
        }
        byte[] allByte = new byte[lengthByte];

        int countLength = 0;
        for (int i = 0; i < values.length; i++) {
            byte[] b = values[i];
            System.arraycopy(b, 0, allByte, countLength, b.length);
            countLength += b.length;
        }
        return allByte;
    }

    /**
     * 对象转数组
     *
     * @param obj
     * @return
     */
    public static byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
            oos.close();
            bos.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return bytes;
    }

    /**
     * byte数组转对象
     *
     * @param bytes
     * @return
     */
    public static Object toObject(byte[] bytes) {
        Object obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
            ois.close();
            bis.close();
        } catch (IOException | ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        return obj;
    }

    /**
     * 从原值提取新值
     *
     * @param srcValue 原值
     * @param from     起始位置,  取值范围（0-31）
     * @param len      长度,      取值范围（0-32）
     * @return 提取后的值
     * <p>
     * example:
     * srcValue 11111111 00000000 11001100 00000011, from 4 ,len 8
     * mask:    00001111 11110000 00000000 00000000
     * result:      1111 0000                      = 0xf0
     */
    public static int getValue(int srcValue, int from, int len) {
        if (from > 31 || from < 0) {
            throw new IllegalArgumentException("error in modify index :" + from);
        }
        if (len > 32 || len < 0) {
            throw new IllegalArgumentException("error in modify length : " + len);
        }
        if (from + len > 32) {
            throw new IllegalArgumentException("modifyFrom + modifyLen should be equals or less than 32, but " + (from + len));
        }
        int value = srcValue;
        value = value << from;
        value = value >>> (32 - len);
        return value;
    }
}


